//
//  ViewController.swift
//  studySwiftControlFlow
//
//  Created by 李想 on 2018/5/14.
//  Copyright © 2018年 李想. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        //函数流
        //Swift 提供了多种流程控制结构,包括可以多次执行任务的while循环，基于特定条件选择执行不同代码分支的if，guard和switch语句  还有控制流程跳转到其他代码位置的break 和continue语句
        
        //Swift 还提供了for,in 用来更简单的遍历数组array  字典dictionary ，区间range 字符串集string 和其他序列类型  Set
        
        //Swift的switch语句比c语言中更加强大，case 还可以匹配很多不同的模式，包括范围匹配，元组tuple和特定类型匹配，switch的case中匹配的值可以声明为临时常量或变量，在case作用域内使用，也可以配合where 来描述更复杂的匹配条件
        //for in循环 可以使用forin 循环来遍历一个集合中的所有元素，例如数组中的元素，范围内的数字或者字符串中的字符
        
        let names = ["nihao","hellp","world"]
        for str in names{
            print(str)
        }
        
        let  dict = ["a":"1","b":"2","c":"3"]
        //遍历字典
        for (key,value) in dict{
            print("\(key) : \(value)")
        }
        
        //若按顺序遍历字典 没有多大意义 多数用在传参
        //若顺序遍历  如果key是 中文 那就借助三方库
        for key in dict.keys.sorted(){
            print("\(key) = \(dict[key])")
        }
        
        //使用 ... 表示一个区间，从0 到 5   ...表示闭区间操作符
        for num in 0...5{
            print(num)
        }
        
        //使用..<  表示从开始位置到 小于的数 不包含小于的数
        for  num in 0..<10{
            print(num)
        }
        
        for index in 1...5 {
            print("\(index) times 5 is \(index * 5)")
        }
        //在例子中，index 是一个每次循环遍历开始时被自动赋值的常量，这种情况下，index 在使用前不需要声明，只需要将它包含在循环声明中，就可以对其进行隐式声明，而无需使用let关键字声明
        
        //如果只单纯的想用下循环 来干别的变量的事 则不需要创建默认常量， 使用 (_)来替代变量名忽略这个值
        let base = 3
        let num = 1
        var result = 1
        for _ in 0...num{
            result *= base
        }
        print(result)
        
        //使用stride(form:to:by:)函数来跳过不需要的标记 stride跨过，步幅
        let skip = 5
        for num in stride(from: 0, to: 60, by: skip){
            print(num)
        }
        //会从初始值开始
        
        //也可以在闭区间用 Stride(form:through:by:) 起到同样作用
        for bun in stride(from: 0, through: 12, by: 3){
            print(bun)
        }
        
        //while 循环会一直巡行到一段语句知道条件编程false 。这类循环适合使用在第一次迭代前，迭代次数位置的情况下，swift 提供两种while 循环形式
        
        //while循环，每次在循环开始时计算条件是否符合
        //repeat-while循环，每次在循环结束时计算条件是否符合
        
        var number = 1;
        while number <= 10 {
            number += 2
            print(number)
        }
        
        let finaly = 25
        var board = [Int](repeating: 0, count: finaly + 1) //这是创建一个初始数组啊  学到了 创建25+1 个 每个都是0
        print(board)
        board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
        board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
        
        var square = 0
        var diceroll = 0
        while square < finaly {
            diceroll += 1
            if diceroll == 7 {
                diceroll = 1
            }
            square += diceroll
            
            if square < board.count{
                square += board[square]
            }
        }
        //md  直接给个棋盘游戏来解释说明 不清楚游戏的 还真有点懵逼 就是记录当前在多少格 符合定好的点 就加减对应的点的值  直到走到末尾格为止
        
        //Repeat-while   while 循环的另一种形式是repeat-while  它和while的区别实在判断循环条件之前，先执行一次循环的代码块，然后重复循环直到条件为false
        //Swift 语言 repeat-while  与 其他语言中 do-while 循环是类似的
        
        var counts = 0
    
        repeat{
            counts += 1
        } while counts <= 11
        print(counts)
        
        
//        repeat-while语句 会比while 语句省去数组越界的检查  现在repeat 语句中取出数组  看情况而定
        
        //swift 提供两种类型的条件语句  if语句和switch语句，通常，当条件较为简单且可能的情况很少时用if语句，而switch语句更适用于条件较复杂，有更多排列的时候，并且switch在需要用到模式匹配（pattern-matching）的情况下回更有用
        
        var testnum = 30
        if testnum <= 32{
            print("太简单了 就是小于32")
        }
        //如果是真则执行第一个语句
        
        if testnum <= 26{
            print("夏天26度舒适")
        }else if(testnum >= 30){
            print("空调极限")
        }
        
        //当不需要完整判断情况的时候，最后的else 语句是可选的
        
        //Switch
        //switch语句会尝试把某个值与若干个模式进行匹配。根据第一个匹配陈赓模式 ，switch语句执行对应的代码，当有可能的情况较多时，通常用switch 语句替换if语句
        var switchnum = 2
        switch switchnum {
        case 1:
            print("1")
        case 2,
             3:
            print("2||3")
        case 4:
        print("4")
        case 5:
            print("5")
        default:
            break
        }
        //当写完时，发现警告已经告诉我 除了 case 2 3  其他行的打印不会被执行  这判断能力有点强  直接帮我匹配完了
        //每行不需要写上break  若多个匹配用同一个结果时，需在条件后加,逗号来隔开再 ：冒号匹配
        
        //switch 语句由多个case 构成，每个由case 关键字开始，为了匹配某些更特定的值，swift提供了几种方法来进行更复杂的模式匹配，这些模式将在本节的稍后部分提到
        //与if语句类似，每一个case都是代码执行的一条分支，switch会决定那一条分支应该被执行，这个流程被称作根据给定的值切换。
        
        //switch语句必须是完备的，这就是说，每一个可能的值都必须至少有一个case分支与之对应，在某些不可能涵盖所有值得情况下，你可以使用默认分支来涵盖其它所有没有对应的值，这个默认分支必须在switch语句的最后面
        let someCharacter: Character = "z"
        switch someCharacter {
        case "a":
            print("The first letter of the alphabet")
        case "z":
            print("The last letter of the alphabet")
        default:
            print("Some other character")
        }
        
        //若写了default: 那就得必须写完整或者不写任何自己的语句、要写上break
        //为什么会翻译成 不存在隐式的贯穿  很是不理解这个名字
        //与c 和oc 的switch 语句不同，当匹配的case 分支中的代码执行完成后，程序会终止switch语句，而不会继续执行下一个case 语句，这也就是说，不需要再case分支中显式使用break语句。这使得switch语句更安全，更易用，也避免了因忘写了break语句而产生的错误。
        //虽然swift中 break 不是必须的，但依然可以写
        
        //每个case 分支必须包含一个语句 若写了case value: 后面什么也不写 会报错
        //为了让单个case 同时匹配两个值，可以将两个值组合成一个符合匹配，并且用逗号分开
        let anotherCharacter: Character = "a"
        switch anotherCharacter {
        case "a", "A": //可以写在一行里 也可以分行写以便可读性
            print("The letter A")
        default:
            print("Not the letter A")
        }
        
        //case 分支模式也可以是一个值得区间，下面的例子展示了如何使用区间匹配来输出任意数字对应的自然语言格式
        
        let casenumber = 31
        let casestr : String
        
        //因为casestr 是没有默认值，是可选值，若是var 则随便  若给赋了初始值 则不能匹配
        switch casenumber {
        case 0:
            casestr = "0"
        case 1..<5:
            casestr = "1-5"
        case 5..<20:
            casestr = "5-20"
        case 20..<40:
            casestr = "20-40"
            
        default:
            break
        }
        
        //case 也可以匹配元组  或者元组中的区间
        //使用 _ 下划线 来匹配所有可能的值
        let  somerange = (1,0)
        switch somerange {
        case (0,0):
            print("匹配0，0")
        case (_,0):
            print("匹配 _,0")
        case (0,_):
            print("匹配 0,_")
        case (-2...2,-2...2):
            print("匹配一个区间的范围")
        default:
            break
        }
        
        //值绑定
        //case 分支允许将匹配的值声明为临时常量或变量，并且在case分支体内使用， -- 这种行为被称为值绑定（value binding),因为匹配的值在case 分支体内，与临时的常量或变量绑定
        
        let point = (2,0)
        switch point {
        case (let x ,0):
            print("case first \(x)")
        case (0,let y):
                print("case scond \(y)")
        case let (x,y):
            print("case x=\(x) y = \(y)")
        default:
            break
        }
        //式子中 let x 或者 let y  或者 let(x,y)  可以理解为 _ 匹配任意值， let (_,_)
        
        
        //可以 将上面的式子 理解 写成下面的式子
        let point1 = (2,0)
        switch point1 {
        case (_ ,0):
            print("case first")
        case (0,_):
            print("case scond")
        case let (_,_):
            print("case all")
            
        //因为已经写出了匹配 所有 就不会在走 default语句 除非 数据项格式不对
        default:
            break
        }
        
        //case 的分支判断中 可以使用 Where 来判断额外条件
        let testpoint = (1,-1)
        switch testpoint {
        case let (x,y) where x == y: //理解为 匹配所有 并且 x 与 y相等
            print("\(x),\(y) where is x == y")
        case let (x,y) where x == -y: //理解为 匹配所有 并且 x 与 -y相等
            print("\(x),\(y) where is x == -y")
        case let (x, y):            //匹配任何值
            print("(\(x), \(y)) is just some arbitrary point")
        default:
            break
        }
        //一开始想着 直接case 判断语句 下面这语句 既然都知道要匹配的值是真是假了 干嘛还要用匹配很傻缺
        //所以 case 分支 是可以写成判断语句的
        let textcode = 1
        var boolvalue : Bool = true
        switch boolvalue {
        case textcode >= 5:
            print("case first")
        case textcode <= 5:
            print("case second")
        default:
            break
        }
        
        var string = "default"
        
        //do sth change string value
        //然后 匹配string 值
        
        //下面的式子是错误 匹配string  所以case 匹配的表达式 都应该是给一个string类型的值出来 不能是别的值 所以还是用where 来表示
//        switch string {
//        case string.isEmpty:
//            <#code#>
//        default:
//            <#code#>
//        }
        
        //where 后面加判断 加操作式  但是where 后面还是要跟表达式
        switch string {
        case let emptyStr where string.isEmpty:
            print("null string")
        case let defaultStr where string == "de":
            print("default")
        case let changeStr where changeStr[...changeStr.index(changeStr.endIndex, offsetBy: -1)] == "default" :
            print("匹配到了 \(changeStr)")
        default:
            break
        }
        //还是要抛弃我这种 乱七八糟的想法
        //理解为 先将let 常量 变为匹配的值，然后拿常量放到 where 后面的判断语句中,且当语句条件为true 是，匹配到的分支才会被执行
        
        //复合匹配
        let char : Character = "a"

        switch char {
        case "a","b","c":
            print("case first")
        case "a","e","f": //此时xcode 已经给出警告说 ”a“ 已经被判断过了，无序再写，所以只会匹配一次
            print("case second")
        default:
            break
        }
        //复合匹配同样包含值绑定,
        let yuanzu = (10,10)
        switch yuanzu {
        case (let case1 ,10),(10,let case1):
//        case (let case1 ,10),(10,let case2): //本来写成两种 常量 但是xcode 会报错 说case1 必须在所有的匹配元素中，意思是复合匹配的每个绑定值必须是同一个 变量或常量的名字  不能重复的创建
            print("x =\(case1) y = \(case1)")
        default:
            break
        }
        //官方翻译为 所有的分支体内 只要任何一个匹配 都已获取到 同样的命名的值
        
        
        
        
        //控制转移语句
        //包含  continue、break、fallthrough、return、throw
        
        //continue 继续  语句会告诉一个循环体like停止本次循环 ，重新开始下次循环，就好像在说 本次循环我已经执行完了，但是并不会离开整个循环体
        
        let world = "hello world"
        var character = ""
        for char in world{
            switch char {
            case "a","b","c","d":
                continue
            default:
                character.append(char)
            }
        }
        print(character)
        //使用了continue 就直接跳出循环，不在执行后续代码，重新下一次循环。
        
        
        //break   break 语句会立刻结束整个控制流的执行，break 可以在switch 或循环语句中使用，用来提前结束switch或循环语句
        
        //循环语句中的break  当在一个循环中使用break 会立刻中断该循环体的执行，然后跳转到表示循环体结束的大括号” } “后的第一行代码，不会再有本次循环的代码被执行，也不会再有下次的循环产生。
        
        
        //switch 语句中的break
        //当在一个switch 代码块中使用break时，会立即中断该switch代码块的执行，并且跳转到表示switch代码块结束的大括号 “}”后的第一行代码
        //这种特性可以被用来匹配或者忽略一个或多个分支。因为swift的switch需要包含所有的分支，而且不允许有为空的分支，有时为了使你的意图更明显，需要特意匹配或者忽略某个分支。那么当你想忽略某个分支时，可以在该分支内写上break语句，当那个分支被匹配到时，分支内的break语句立即结束switch 代码块
        
        //当一个switch分支仅仅包含注释时，会被报编译错误，注释不是代码语句而且也不能让switch 分支打到忽略的效果，你应该使用break 来忽略某个分支。
        
        let numberSymbol: Character = "三"  // 简体中文里的数字 3
        var possibleIntegerValue: Int?
        switch numberSymbol {
        case "1", "١", "一", "๑":
            possibleIntegerValue = 1
        case "2", "٢", "二", "๒":
            possibleIntegerValue = 2
        case "3", "٣", "三", "๓":
            possibleIntegerValue = 3
        case "4", "٤", "四", "๔":
            possibleIntegerValue = 4
        default:
            break
        }
        if let integerValue = possibleIntegerValue {
            print("The integer value of \(numberSymbol) is \(integerValue).")
        } else {
            print("An integer value could not be found for \(numberSymbol).")
        }
        // 输出 "The integer value of 三 is 3."
        
        
        //贯穿
        //在swift 里，switch 语句不会从上一个case 分支跳转到下一个case分支中，相反，只要第一个匹配的case分支完成了它所需要执行的语句，整个switch代码块完成了它的执行，相比之下。c语言要求你显式的插入break语句到每个case分支的末尾来阻止自动落入到下一个case分支.swift的这种避免默认落入到下一个分支中的特性意味着它的switch功能要比c语言的更加清晰和可预测，可以避免无意识的执行多个case分支从而引发的错误。
        //如果你确实需要c风格的贯穿的特性，你可以在每个需要改特性的case 分支中使用fallthrough关键字。下面的例子找那个使用fallthrough来创建一个数字的描述语句
        
        let numm = 5
        var nummdes = "number \(numm) is"
        switch numm {
        case 5,6,7,8:
            nummdes += "get this"
            fallthrough
        case 5,7,8,9 :
            nummdes += "get second"
        default:
            break
        }
        print(nummdes)
        
        //fallthrough 不会默认执行break 结束整个switch 语句  会继续走下一个case 语句 直到走完或者遇到break
        
        //带标签的语句  在swift中，你可以在循环和条件语句中嵌套循环体和条件语句来创造复杂的控制流结构，并且，循环体和条件语句都可以使用break语句来提前结束整个代码块，因此，显式的指明break语句想要终止的是哪个循环体或者条件语句，会很有用，类似地，如果你有许多嵌套的循环体，显式指明continue语句想要影响哪一个循环体也会非常有用.
        
        //标签 statement label来标记一个循环体或者条件语句，对于一个条件语句，你可以使用break加标签的方式，来结束这个被标记的语句，对于一个循环语句，你可以使用break 或者continue加标签，来结束或者继续这条被标记语句的执行
        
        //声明一个带标签的语句是通过在该语句的关键词的同一行前面防止一个标签，作为这个语句的前导关键字 introducor keyword 并且该标签后面跟随一个冒号
//        label name : while condition { statements}
        
        //意思应该为循环体内 嵌套一个循环体或者一个switch 语句  在最外层的主循环体前加一个标签 与冒号 来代表这个最外层主要循环体,然后内层的循环体匹配到一个条件正好满足条件，然后要求整个循环体结束，不再执行。或者跳过这个 继续下次
        
        let outnum = 11
        let innum = 22
        
        var countnum = 0
        
        outfor:  for i in 0..<4{
            infor: for j in 0..<4{
                countnum = i * 10 + j
                inswitch:  switch countnum {
                            case outnum:
                                print("匹配到了 11 执行continue操作 跳过内层for当前循环")
                                continue infor
//                                fallthrough 想着 我只是结束内层循环 但switch语句还是继续走啊 能不能贯穿到默认去
                            case innum :
                                print("匹配到了22 结束整个外层循环")
                                break outfor
                            default:
                                break
                            }
                            print("结束执行switch \(countnum)")
                // 打印得出 匹配到了11 后结束内层循环，switch 也停止了，内层循环末尾的打印当匹配到11后也没有执行，直接在匹配到了11 后就没再往下走过。
                //在匹配到了22后也没有执行内层循环末尾的打印，直接结束了整个外层循环
                
                
                
                    }
                    print(countnum)
                }
        
        //提前退出 想if语句一样，guard 的执行取决于一个表达式的布尔值，我们可以使用guard 语句来要求条件必须为真时，以执行guard 语句后的代码，不同于if 语句，一个guard 语句总是有一个else 从句，如果条件不为真则执行else 从句中的代码。
        //如果条件不被满足，在else分支上的代码就会被执行，这个分支必须转义控制以退出guard语句出现的代码段。它可以用控制转义语句如 return，break，continue，或者throw做这件事，或者调用一个不反悔的方法或函数，例如fatalerror（）
        //相比于可以实现同样功能的if语句，按需使用guard 语句会提升我们代码的可读性，它可以使你的代码连贯的被执行 而不需要将它抱在else块中 。它可以使你在紧邻条件判断的地方，处理违规的情况。
        
        //个人觉得可以用在 各种格式判断上 如手机号，邮箱，身份证等等正则表达式上，或者在一个表单页面，很多填写页面做未填写检查
        conname(person: ["name":"lili"])
        conname(person:["name":"lili","where":"安徽"])
        conname(person:["noname":"noname"])
        
        //检测API可用性
        //swift 内置支持检查API可用性 ，这可以确保我们不会在当前部署机器上，不小心使用了不可用的API
        //编译器使用SDK中的可用信息来验证我们的代码中使用的所有API 在项目指定的步数目标上是否可用，如果我们尝试使用一个不可用的API,SWift会在编译时报错
        
        //我们在if或guard 语句中使用可用性条件，（availablity condition） 去有条件的执行一段代码，来在运行时判断调用的API 是否可用。编译器使用从可用性条件语句中获取的信息去验证，在这个代码块中调用的API 是否可用
        
        if #available(iOS 10, macOS 10.12, *){
            print("支持ios 10 和macOS 10.12")
        
        }else{
            print("不支持")
        }
        
        //在一般形式中，可用性条件使用了一个平台名字和版本的列表，平台名字可以使iOS，macOS，watchOS 和tvOS
    }

    
    func conname(person :[String : String]){
        guard let name = person["name"] else {
            print("没有名字的你 你好")
            return;
        }
        
        guard let location = person["where"] else {
            print("\(name)不知道你在哪")
            return
        }
        
        print("\(name)  \(location) 天气怎么样")
    }
    
    
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

